package com.hiraeth.modules.monitor.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.hiraeth.common.config.MonitorConfiguration;
import com.hiraeth.common.exception.RRException;
import com.hiraeth.common.utils.OkHttpCli;
import com.hiraeth.common.utils.PrometheusUtils;
import com.hiraeth.common.utils.R;
import com.hiraeth.modules.monitor.model.PrometheusConfig;
import com.hiraeth.modules.monitor.model.ScrapeConfig;
import com.hiraeth.modules.monitor.service.JobService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.yaml.snakeyaml.Yaml;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class JobServiceImpl implements JobService {

    @Autowired
    private MonitorConfiguration monitorConfiguration;

    @Autowired
    private OkHttpCli okHttpCli;
    /**
     * 查询promethus job配置列表
     * @return
     */
    @Override
    public List<ScrapeConfig> getJobList() {
        // 读取配置文件的方式查询配置，需要考虑global配置，因此改为查询prometheus API的方式获取prometheus配置信息
        /*Representer representer = new Representer();
        representer.getPropertyUtils().setSkipMissingProperties(true);
        Yaml yaml = new Yaml(representer);
        BufferedInputStream inputStream = FileUtil.getInputStream(FileUtil.newFile(monitorConfiguration.getPrometheusYml()));
        Object load = yaml.load(inputStream);
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RRException(e.getMessage());
        }
        // transform to json then to java bean
        String json = JSONObject.toJSONString(load);
        PrometheusConfig prometheusConfig = JSON.parseObject(json, PrometheusConfig.class);
        return prometheusConfig.getScrape_configs();*/

//        JSONObject result = restTemplate.getForObject("http://" + host+ ":" + prometheusPort + "/api/v1/status/config", JSONObject.class);
        return getPrometheusConfig().getScrape_configs();
    }

    /**
     * 保存static job
     *
     * @param scrapeConfig
     * @return
     */
    @Override
    public R saveStatiConfigJob(ScrapeConfig scrapeConfig) {
        PrometheusConfig prometheusConfig = getPrometheusConfig();

        // modified
        if (prometheusConfig == null) {
            prometheusConfig = new PrometheusConfig();
        }
        // if scrape_configs is null,new it
        if (prometheusConfig.getScrape_configs() == null) {
            List<ScrapeConfig> scrapeConfigs = Lists.newArrayList();
            prometheusConfig.setScrape_configs(scrapeConfigs);
        }

        if (PrometheusUtils.isAlreadyExist(prometheusConfig.getScrape_configs(), scrapeConfig.getJob_name())) {
            // 配置文件中已存在与待添加的job_name同名的scrape_config
            return R.error("已存在同名任务。");
        }else {
            prometheusConfig.getScrape_configs().add(scrapeConfig);
            return writePrometheusCnfig(prometheusConfig, monitorConfiguration.getPrometheusYml());
        }
    }

    /**
     * 更新static job
     *
     * @param scrapeConfig
     * @return
     */
    @Override
    public R updateStatiConfigJob(ScrapeConfig scrapeConfig) {
        PrometheusConfig prometheusConfig = getPrometheusConfig();
        if (prometheusConfig == null
                || prometheusConfig.getScrape_configs() == null
                || !PrometheusUtils.isAlreadyExist(prometheusConfig.getScrape_configs(), scrapeConfig.getJob_name())) {
            // 配置文件中已存在与待添加的job_name同名的scrape_config
            return R.error("要修改的任务不存在。");
        }else{
            // 组装完scrape_config后，移除原有的scrape_config，替换为新的配置内容
            prometheusConfig.getScrape_configs().removeIf(sc -> sc.getJob_name().equals(scrapeConfig.getJob_name()));
            prometheusConfig.getScrape_configs().add(scrapeConfig);
            return writePrometheusCnfig(prometheusConfig, monitorConfiguration.getPrometheusYml());
        }
    }

    /**
     * 根据job名称删除static job
     *
     * @param job_name
     * @return
     */
    @Override
    public R deleteStatiConfigJob(String job_name) {
        PrometheusConfig prometheusConfig = getPrometheusConfig();
        if(prometheusConfig != null && prometheusConfig.getScrape_configs() != null) {
            prometheusConfig.getScrape_configs().removeIf(sc -> sc.getJob_name().equals(job_name));
        }
        return writePrometheusCnfig(prometheusConfig, monitorConfiguration.getPrometheusYml());
    }

    /**
     * 获取全部prometheus配置
     * @return
     */
    public PrometheusConfig getPrometheusConfig(){
        String result = okHttpCli.doGet("http://127.0.0.1:9090/api/v1/status/config");
        JSONObject resultJsonObject = JSONObject.parseObject(result);
        if (resultJsonObject.containsKey("status") && resultJsonObject.get("status").equals("success")) {
            String prometheusConfigString = (String)((Map)resultJsonObject.get("data")).get("yaml");
            Yaml yaml = new Yaml();
            Object load = yaml.load(prometheusConfigString);
            String json = JSONObject.toJSONString(load);
            PrometheusConfig prometheusConfig = JSON.parseObject(json, PrometheusConfig.class);
            return prometheusConfig;
        }else{
            throw new RRException("从prometheus API中查询配置失败。");
        }
    }

    /**
     * 将prometheus配置对象转为yml回写到prometheus配置文件中，并重启prometheus
     * @param prometheusConfig prometheus配置对象
     * @param prometheusYmlAbsPath prometheus.yml绝对路径
     * @return
     */
    private R writePrometheusCnfig(PrometheusConfig prometheusConfig, String prometheusYmlAbsPath){
        // reproduce to json string then to Object
        String jsonString = JSONObject.toJSONString(prometheusConfig);
        Object object = JSONObject.parse(jsonString);


        // write to file
        Yaml yaml = new Yaml();
        String dump = yaml.dumpAsMap(object);
        FileUtil.writeString(dump, FileUtil.newFile(prometheusYmlAbsPath), CharsetUtil.CHARSET_UTF_8);

        // reload config
        HttpRequest post = HttpRequest.post("http://127.0.0.1:9090/-/reload");
        HttpResponse response = post.execute();
        if (response.getStatus() == 200) {
            return R.ok();
        } else {
            return R.error("配置刷新接口请求失败");
        }
    }
}
